﻿using System.Collections.Concurrent;
using System.Collections.Specialized;
using System.Web;
using System.Threading;
using System.IO;
using System;
using System.Xml.Linq;

namespace Fx.Mvc.Language
{
    public class LanguageProvider
    {
        public const string LocaleFileExtension = "xml";
        public const string DefaultCulture = "vi-vn";
        public const string CultureKey = "_culture_";

        private readonly ConcurrentDictionary<string, StringDictionary> _caches;

        public LanguageProvider()
        {
            _caches = new ConcurrentDictionary<string, StringDictionary>();
        }

        #region Properties
        
        public ConcurrentDictionary<string, StringDictionary> Languages
        {
            get { return _caches; }
        }

        #endregion

        #region Internal protected
        
        internal protected void LoadLanguage(string languageDirectory)
        {
            var languagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin", languageDirectory);
            if (!Directory.Exists(languagePath)) return;
            var files = Directory.GetFiles(languagePath, "*." + LocaleFileExtension);
            foreach (var file in files)
            {
                var culture = GetCultureFromFileName(file);
                var doc = XDocument.Load(file);
                var dictionary = new StringDictionary();
                foreach (var item in doc.Descendants("item"))
                {
                    var keyAttribute = item.Attribute("key");
                    var valueAttribute = item.Attribute("value");
                    if (keyAttribute == null || valueAttribute == null) continue;
                    if (dictionary.ContainsKey(keyAttribute.Value))
                    {
                        dictionary[keyAttribute.Value] = valueAttribute.Value;
                    }
                    else
                    {
                        dictionary.Add(keyAttribute.Value, valueAttribute.Value);
                    }
                }
                _caches.AddOrUpdate(culture, dictionary, delegate { return dictionary; });
            }
        }

        internal protected string GetCultureFromFileName(string fielPath)
        {
            var fileInfo = new FileInfo(fielPath);
            var fileParts = fileInfo.Name.Split(new[] {'.'});
            return fileParts.Length >= 2 ? fileParts[0] : DefaultCulture;
        }

        #endregion

        public string Translate(string key)
        {
            return Translate(key, string.Empty);
        }

        public string Translate(string key, string defaultValue)
        {
            StringDictionary stringDictionary;
            var culture = GetCulture(HttpContext.Current);
            if (_caches.TryGetValue(culture, out stringDictionary))
            {
                if (stringDictionary.ContainsKey(key))
                {
                    var value = stringDictionary[key];
                    return value;
                }
            }
            return defaultValue;
        }

        #region Private static methods

        internal static string GetCulture(HttpContext context)
        {
            var code = GetCookieCulture(context);

            if (string.IsNullOrEmpty(code))
                code = GetCountryCulture(context);
            return code;
        }

        internal static string GetThreadCulture()
        {
            return Thread.CurrentThread.CurrentCulture.Name;
        }

        internal static string GetCountryCulture(HttpContext context)
        {
            //TODO: use any website service to get country culture.
            return DefaultCulture;
        }

        internal static string GetCookieCulture(HttpContext context)
        {
            if (context == null) return null;

            var cookie = context.Request.Cookies[CultureKey];
            if (cookie == null || string.IsNullOrEmpty(cookie.Value))
            {
                return DefaultCulture;
            }
            return cookie.Value;
        }

        #endregion
    }
}